﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Input;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Utils;
using PloobsEngine.Features;
using PloobsEngine.Commands;
using PloobsEngineDemo3;
using PloobsEngine.Light;
using PloobsEngine.DataAquisition;
using Microsoft.Xna.Framework.Input;

namespace Etapa1.Screens
{
    public class InstancingScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;        
        InstancingDinamicNormalDeferred shader ;
        ICamera cam;        

        public InstancingScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();
            mundo = new BrutalForceWorld(physicWorld);                                    
        }

        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            Matrix[] m = new Matrix[shader.Instances.Count()];
            //if (Keyboard.GetState().IsKeyDown(Keys.J))
            //{
            for (int i = 0; i < shader.Instances.Count(); i++)
            {
                m[i] = shader.Instances[i].World * Matrix.CreateTranslation(StaticRandom.RandomDirection());
            }
            shader.ChangeDynamicVertexBuffer(m);
            //}            

            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
        }        
        
        public override void LoadContent(EngineStuff es)
        {
            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            base.LoadContent(es);

            #region Models

            //int count = 500* 500;
            int count = 50 * 50;
            Matrix[] m = new Matrix[count];
            float disp = 9;
            int k = 0;
            for (int i = 0; i < Math.Sqrt(count); i++)
            {
                for (int j = 0; j < Math.Sqrt(count); j++)
                {
                    m[k++] = Matrix.CreateTranslation(new Vector3(i * disp, 100, j * disp));
                }
            }

            ////dynamic instancing
            //{

                ///ilha de sempre 
                {
                    SimpleModel model = new SimpleModel("..\\Content\\Model\\cenario");
                    model.LoadModelo();
                    IPhysicObject phisic = new TriangleMeshObject(Vector3.Zero, model);
                    CustomDeferred shad = new CustomDeferred(false, false, false, false);
                    shad.SpecularIntensity = 0;
                    shad.SpecularPower = 0;
                    shad.Initialize();
                    IMaterial material = new Material(shad, MaterialType.DEFERRED);
                    IObject obj6 = new SimpleObject(material, phisic, model);
                    mundo.AddObject(obj6);
                }
                                
                ///objetos fisicos
                AgregatedPhysicObject agregated = new AgregatedPhysicObject();
                for (int i = 0; i < count; i++)
                {
                    IPhysicObject px = new BoxObject(m[i].Translation, 1, 10);
                    agregated.PhysicsObjects.Add(px);
                }

                ///modelo q representa todas as instancias
                IModelo sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\blue");
                sm.LoadModelo();
                //shader = new InstancingDinamicNormalDeferred(InstanceTechnich.TEXTURE, m, null);
                shader = new InstancingDinamicNormalDeferred(InstanceTechnich.TEXTURE, agregated, null);
                shader.SpecularIntensity = 0.3f;
                shader.SpecularPower = 50;
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj3 = new SimpleObject(mat, agregated, sm);
                mundo.AddObject(obj3);
            
            ///static instancing
            //{
            //    IModelo sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
            //    sm.LoadModelo();
            //    IPhysicObject pi = new DummyPhysicObject();
            //    InstancingStaticNormalDeferred shaderS = new InstancingStaticNormalDeferred(count, InstanceTechnich.COLOR, m, null);
            //    shaderS.SpecularIntensity = 0.3f;
            //    shaderS.SpecularPower = 50;
            //    shaderS.Initialize();
            //    IMaterial mat = new Material(shaderS, MaterialType.DEFERRED);
            //    IObject obj3 = new SimpleObject(mat, pi, sm);
            //    mundo.AddObject(obj3);
            //}

            ///normal
            //{
            //    for (int i = 0; i < count; i++)
            //    {

            //        SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
            //        sm.LoadModelo();
            //        IPhysicObject pi = new GhostObject(m[i].Translation, Matrix.Identity, Vector3.One);
            //        NormalDeferred shader = new NormalDeferred();
            //        shader.SpecularIntensity = 0.3f;
            //        shader.SpecularPower = 50;
            //        shader.Initialize();
            //        IMaterial mat = new Material(shader, MaterialType.DEFERRED);
            //        IObject obj3 = new SimpleObject(mat, pi, sm);
            //        mundo.AddObject(obj3);
            //    }
            //}


            #endregion

            cam = new CameraFirstPerson(true);
            cam.FarPlane = 3000;


            #region NormalLight

            #region NormalLight
            DirectionalLight ld1 = new DirectionalLight(Vector3.Left, Color.White);
            DirectionalLight ld2 = new DirectionalLight(Vector3.Right, Color.White);
            DirectionalLight ld3 = new DirectionalLight(Vector3.Backward, Color.White);
            DirectionalLight ld4 = new DirectionalLight(Vector3.Forward, Color.White);
            DirectionalLight ld5 = new DirectionalLight(Vector3.Down, Color.White);
            float li = 0.7f;
            ld1.LightIntensity = li;
            ld2.LightIntensity = li;
            ld3.LightIntensity = li;
            ld4.LightIntensity = li;
            ld5.LightIntensity = li;
            //mundo.AddLight(ld1);
            //mundo.AddLight(ld2);
            mundo.AddLight(ld3);
            mundo.AddLight(ld4);
            mundo.AddLight(ld5);
            #endregion



            #endregion

            ////Criacao de uma Tecnica
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            dr.isDebug = true;
            //dr.RestoreDepth = RestoreDepthOption.NONE;
            //dr.DeferredFinalCombination.SaveToTexture = false;
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            mundo.AddCamera(cam);
            this.World = mundo;
        }

    }
}

